package com.iwhalecloud.uncc.common;

import java.util.AbstractQueue;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;

import com.iwhalecloud.uncc.dao.SysConfigDao;
import com.iwhalecloud.uncc.db.DatasourceContextHolder;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;


import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;

@Slf4j
@Component
public class SequenceCreator {
    private static ConcurrentMap<String, String> gidUrlMap = new ConcurrentHashMap<String, String>();
    private static ConcurrentMap<String, AbstractQueue<Long>> seqpool = new ConcurrentHashMap<String, AbstractQueue<Long>>();

    @Autowired
    private SysConfigDao sysConfigDao;
    @Resource
    private RestTemplate balancedRestTemplate;

    public static Long getSeq(String name) {
        while (true) {
            try {
                String poolName = name;
                Long seq = seqpool.get(poolName).poll();
                if (seq != null) {
                    return seq;
                } else {
                    log.info("can not get seq_id from [" + name + "] at local cache");
                    Thread.sleep(1000);
                }
            } catch (Exception ex) {
                log.error("seq name:" + name + ExceptionUtils.getStackTrace(ex));
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    log.error(ExceptionUtils.getStackTrace(e));
                }
            }
        }

    }

    public void init() {
        ResourceBundle res = ResourceBundle.getBundle("sequence");
        Set<String> seqs = res.keySet();
        Iterator<String> it = seqs.iterator();
        while (it.hasNext()) {
            String key = it.next();
            String value = res.getString(key);
            String[] args = value.split(",");

            String queueName = key;
            AbstractQueue<Long> queue = new ConcurrentLinkedQueue<Long>();
            seqpool.put(key, queue);// 设置队列到池中

            log.info("initing sequence=" + queueName + "...");
            SequenceHandler seq = new SequenceHandler(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2]),
                    queue);
            Thread t = new Thread(seq, queueName + "-Handler-");
            t.start();
        }
    }

    class SequenceHandler implements Runnable {

        private String seqName;
        private int maxSize;
        private int batchSize;
        private AbstractQueue<Long> seqQueue;

        public SequenceHandler(String seqName, int maxSize, int batchSize, AbstractQueue<Long> seqQueue) {
            this.seqName = seqName;
            this.maxSize = maxSize;
            this.batchSize = batchSize;
            this.seqQueue = seqQueue;
        }

        @Override
        public void run() {
            String seqGetMod = sysConfigDao.getSysConfig(SysConstant.UC_SEQ_MOD);
            String gidUrl = sysConfigDao.getSysConfig(SysConstant.GID_URL);
            String sysCode = null;
            if(seqName.contains(".")){
                // 非本系统序列
                sysCode = seqName.split("\\.")[0];
                seqName = seqName.split("\\.")[1];
                gidUrl = sysConfigDao.getSysConfig(sysCode + "_" + SysConstant.GID_URL);
            }
            while (true) {
                try {
                    if (seqQueue.size() < maxSize) {
                        if ("CTG".equalsIgnoreCase(seqGetMod)) {
                            DatasourceContextHolder.setDs(sysCode);
                            List<Long> seqsList = sysConfigDao.getCtgSeq(seqName, batchSize);
                            seqQueue.addAll(seqsList);
                        } else {
                            Long seq = null;
                            if ("LOCAL".equalsIgnoreCase(seqGetMod)) {
                                seq = sysConfigDao.getLocalSeq(seqName, batchSize);
                            } else if ("MYSQL".equalsIgnoreCase(seqGetMod)) {
                                seq = balancedRestTemplate.getForObject(gidUrl, Long.class, seqName);
                            } else {
                                DatasourceContextHolder.setDs(sysCode);
                                seq = sysConfigDao.getSimpleSeq(seqName);
                            }
                            if (seq != null) {
                                List<Long> temp = new ArrayList<Long>();
                                for (int i = 0; i < batchSize; i++) {
                                    Long s = seq++;
                                    temp.add(s);
                                }
                                seqQueue.addAll(temp);
                            } else {
                                throw new Exception(seqName + " return null !~~");
                            }
                        }

                    } else {
                        Thread.sleep(10);
                    }
                } catch (Exception ex) {
                    log.error(ExceptionUtils.getStackTrace(ex));
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        log.error(ExceptionUtils.getStackTrace(e));
                    }
                }
            }
        }
    }
}
